package com.googlecode.ebasys.entity;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.PersistenceException;
import javax.persistence.PrePersist;
import javax.persistence.Table;

/**
 * User entity.
 * 
 * Represents User concept of the system. A User is someone who can log in. User
 * can have permissions, he/she can be assigned to a {@link Group} (many to
 * many).
 * 
 * User entity should not be overburndened with embedded functionality and
 * relations, system should use the User as it is, without modifications. I.e.,
 * A {@link Group} should have a collection of users associated to it, but User
 * object has no need of being aware of this relation. User Data Access Object
 * should be responsible for getting collection of {@link Group} that User
 * belongs to. This may not be the best choice for performance, however such an
 * approach will be open for extension, new modules may reuse concept of User as
 * it is without modifying the core code.
 * 
 * @author Tomas Varaneckas
 * @version $Id: User.java 59 2009-02-09 16:45:24Z tomas.varaneckas $
 */
@Entity
@Table(name = "eba_user")
public class User extends PersistentEntity {

    /**
     * Serial Version UID
     */
    private static final long serialVersionUID = -922356718059076205L;

    /**
     * Username. Must be unique. Can be used for logging in.
     */
    @Column(name = "username", unique = true, nullable = false)
    private String userName;

    /**
     * Full name, i.e. "John Smith"
     */
    @Column(name = "fullname")
    private String fullName;

    /**
     * Valid e-mail address
     */
    @Column(name = "email")
    private String email;
    
    /**
     * Groups that user belongs to
     */
    @ManyToMany(targetEntity=Group.class, cascade=CascadeType.PERSIST)
    private List<Group> groups;
    
    /**
     * Validates the creation of new User.
     */
    @PrePersist
    protected void validateCreate() {
        if (userName == null || userName.trim().length() == 0) {
            throw new PersistenceException("Username is required!");
        }
    }

    /**
     * Gets the username
     * 
     * @return username
     */
    public String getUserName() {
        return userName;
    }

    /**
     * Sets the username
     * 
     * @param userName
     *            username to be set
     */
    public void setUserName(final String userName) {
        this.userName = userName;
    }

    /**
     * Gets the full name
     * 
     * @return full name of this user
     */
    public String getFullName() {
        return fullName;
    }

    /**
     * Sets the full name
     * 
     * @param fullName
     *            full name to be set (i.e. "John Smith")
     */
    public void setFullName(final String fullName) {
        this.fullName = fullName;
    }

    /**
     * Gets e-mail address of this user
     * 
     * @return e-mail address
     */
    public String getEmail() {
        return email;
    }

    /**
     * Sets e-mail address of this user
     * 
     * @param email
     *            e-mail address to be set (i.e. "john.smith@example.com")
     */
    public void setEmail(String email) {
        this.email = email;
    }
    
    /**
     * Gets user's {@link Group}s
     * 
     * @return groups user belongs to
     */
    public List<Group> getGroups() {
        if (groups == null) {
            groups = new ArrayList<Group>();
        }
        return groups;
    }

    /**
     * Sets user's {@link Group}s
     * 
     * @param groups
     */
    public void setGroups(final List<Group> groups) {
        this.groups = groups;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + ((email == null) ? 0 : email.hashCode());
        result = prime * result
                + ((fullName == null) ? 0 : fullName.hashCode());
        result = prime * result
                + ((userName == null) ? 0 : userName.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (email == null) {
            if (other.email != null)
                return false;
        } else if (!email.equals(other.email))
            return false;
        if (fullName == null) {
            if (other.fullName != null)
                return false;
        } else if (!fullName.equals(other.fullName))
            return false;
        if (userName == null) {
            if (other.userName != null)
                return false;
        } else if (!userName.equals(other.userName))
            return false;
        return true;
    }

    /**
     * A human friendly version of {@link Object#toString()}
     */
    @Override
    public String toString() {
        return new StringBuilder("{User: [")
            .append(id).append("][")
            .append(userName).append("][")
            .append(fullName).append("][")
            .append(email).append("]}")
            .toString();
    }

}
